﻿namespace HZY.Framework.DependencyInjection.SourceGenerator;

/// <summary>
/// 自动注册 di 服务
/// </summary>
[Generator]
public class AutoRegisterDependencyInjectionGenerator : ISourceGenerator
{
    private const string StringPr = """
                                    
                                     /*
                                     * *******************************************************
                                     *
                                     * 作者：hzy
                                     *
                                     * 开源地址：https://gitee.com/hzy6
                                     *
                                     * *******************************************************
                                     */
                                            
                                    """;

    private const string nameSpaceString = "HZY.Framework.DependencyInjection.SourceGenerator";

    public void Initialize(GeneratorInitializationContext context)
    {
        // 注册一个语法接收器，它会在编译时收集所有的类和它们的公共方法
        context.RegisterForSyntaxNotifications(() => new SyntaxReceiver());
    }

    public void Execute(GeneratorExecutionContext context)
    {
        //Debugger.Launch();

        // 获取语法接收器，并检查它是否收集到了任何类
        if (context.SyntaxReceiver is SyntaxReceiver receiver && receiver.Classes.Any())
        {
            AutoRegisterDependencyInjection(context, receiver.Classes);

            //CreateConstructionClass(context, receiver.Classes);
        }
    }

    private class SyntaxReceiver : ISyntaxReceiver
    {
        public List<ClassDeclarationSyntax> Classes { get; } = new List<ClassDeclarationSyntax>();

        public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
        {
            if (syntaxNode is ClassDeclarationSyntax classDeclarationSyntax)
            {
                Classes.Add(classDeclarationSyntax);
            }
        }
    }

    /// <summary>
    /// 自动注册 di 
    /// </summary>
    /// <param name="context"></param>
    /// <param name="classes"></param>
    public void AutoRegisterDependencyInjection(GeneratorExecutionContext context, List<ClassDeclarationSyntax> classes)
    {
        var registrations = new StringBuilder();

        foreach (var @class in classes)
        {
            // 获取类的命名空间
            var namespaceName = @class.Parent is NamespaceDeclarationSyntax namespaceDeclaration
                ? namespaceDeclaration.Name.ToString()
                : @class.Parent is FileScopedNamespaceDeclarationSyntax namespaceDeclarationSyntax
                    ? namespaceDeclarationSyntax.Name.ToString()
                    : null;
            // 获取类名称
            // var className = @class.Identifier.Text;
            // 获取所有的字段符号
            var classSymbol = context.Compilation.GetSemanticModel(@class.SyntaxTree).GetDeclaredSymbol(@class);
            if (classSymbol == null) continue;

            // 检查泛型 并且泛型 T 类型是具体的类型
            if (classSymbol.IsGenericType)
            {
                // T 不是 具体类型的 要跳过
                if (!CheckGenericity(classSymbol))
                {
                    continue;
                }
            }

            // 查找组件特性
            var componentAttribute = CheckComponentAttribute(classSymbol);
            if (componentAttribute == null) continue;

            // 获取实现类型，即被标记的类的全名
            var implementationType = classSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);

            // 获取参数的值
            var interfaceType = string.Empty;
            var serviceType = "Transient";

            #region 处理 识别 泛型接口

            if (componentAttribute.AttributeClass is { } namedTypeSymbol)
            {
                if (namedTypeSymbol.TypeArguments.Any())
                {
                    var argInterfaceType = namedTypeSymbol.TypeArguments[0];

                    interfaceType = argInterfaceType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
                }
            }

            #endregion

            #region 判断是否有构造函数的参数

            if (componentAttribute.ApplicationSyntaxReference != null)
            {
                // 获取特性的语法引用
                var syntaxReference = componentAttribute.ApplicationSyntaxReference;

                // 获取特性的语法节点
                var syntaxNode = syntaxReference.GetSyntax();

                // 将语法节点转换为 AttributeSyntax
                var attributeSyntax = syntaxNode as AttributeSyntax;

                // 获取特性的构造参数
                var constructorArguments = attributeSyntax?.ArgumentList?.Arguments;

                // 判断是否有构造函数 的参数
                if (constructorArguments != null && constructorArguments.Value.Count > 0)
                {
                    if (constructorArguments.Value[0].Expression is MemberAccessExpressionSyntax
                        memberAccessExpressionSyntax)
                    {
                        serviceType = memberAccessExpressionSyntax.Name.Identifier.ValueText.ToString();
                    }
                }
            }

            #endregion

            // 根据注入类型生成相应的代码行
            switch (serviceType)
            {
                case "Transient":
                    registrations.AppendLine(string.IsNullOrEmpty(interfaceType)
                        ? $"        services.AddTransient<{implementationType}>();"
                        : $"        services.AddTransient<{interfaceType}, {implementationType}>();");
                    break;
                case "Scoped":
                    registrations.AppendLine(string.IsNullOrEmpty(interfaceType)
                        ? $"        services.AddScoped<{implementationType}>();"
                        : $"        services.AddScoped<{interfaceType}, {implementationType}>();");
                    break;
                case "Singleton":
                    registrations.AppendLine(string.IsNullOrEmpty(interfaceType)
                        ? $"        services.AddSingleton<{implementationType}>();"
                        : $"        services.AddSingleton<{interfaceType}, {implementationType}>();");
                    break;
            }
        }

        // 生成一个类，该类包含一个方法，该方法将所有带有 "Inject" 特性的类注入到DependencyInjection容器中
        var registrationClass = $$"""

                                  {{StringPr}}
                                  // <auto-generated/>
                                  namespace Microsoft.Extensions.DependencyInjection;

                                  public static partial class DependencyInjectionGeneratorExtensions
                                  {
                                      public static void AddDependencyInjection{{GetAssemblyName(context.Compilation)}}(this IServiceCollection services)
                                      {
                                  {{registrations}}
                                      }
                                  }

                                  """;

        context.AddSource("DependencyInjectionGeneratorExtensions.g", SourceText.From(registrationClass, Encoding.UTF8));
    }

    /// <summary>
    /// 获取程序集
    /// </summary>
    /// <param name="compilation"></param>
    /// <returns></returns>
    private static string GetAssemblyName(Compilation compilation)
    {
        var assemblyName = compilation.AssemblyName ?? string.Empty;
        return new string(assemblyName.Where(IsAllowChar).ToArray());

        static bool IsAllowChar(char c)
        {
            return ('0' <= c && c <= '9') || ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z');
        }
    }

    /// <summary>
    /// 检查一个类是否为泛型 且泛型类型是 具体的类型
    /// </summary>
    /// <returns></returns>
    private bool CheckGenericity(INamedTypeSymbol namedTypeSymbol)
    {
        var result = false;

        if (namedTypeSymbol.TypeArguments.Any())
        {
            foreach (var typeArgument in namedTypeSymbol.TypeArguments)
            {
                // 判断泛型参数是否是特定类型
                if (typeArgument.TypeKind != TypeKind.TypeParameter)
                {
                    // 这是一个泛型类型参数，例如 T
                    result = true; break;
                }
            }
        }

        return result;
    }

    /// <summary>
    /// 递归检查 类型 中的 特性
    /// </summary>
    /// <param name="namedTypeSymbol"></param>
    /// <returns></returns>
    private AttributeData? CheckComponentAttribute(INamedTypeSymbol? namedTypeSymbol)
    {
        if (namedTypeSymbol == null || namedTypeSymbol?.Name == "Object") return null;

        var componentAttribute = namedTypeSymbol!.GetAttributes()
                        .Where(w => w.AttributeClass != null)
                        .FirstOrDefault(x =>
                            x.AttributeClass!.ToDisplayString().StartsWith(nameSpaceString + ".ComponentAttribute") ||
                            x.AttributeClass!.ToDisplayString().StartsWith(nameSpaceString + ".Component") ||
                            x.AttributeClass!.Name.StartsWith("ComponentAttribute") ||
                            x.AttributeClass!.Name.StartsWith("Component")
                            );
        if (componentAttribute == null)
        {
            return CheckComponentAttribute(namedTypeSymbol.BaseType);
        }

        return componentAttribute;
    }














    /// <summary>
    /// 自动生成类的构造 根据特性 InjectAttribute
    /// </summary>
    /// <param name="context"></param>
    /// <param name="classes"></param>
    private void CreateConstructionClass(GeneratorExecutionContext context, List<ClassDeclarationSyntax> classes)
    {

        context.AddSource($"InjectAttribute.g.cs", SourceText.From($$"""
        {{StringPr}}
        using System.Text;

        // <auto-generated/>

        namespace HZY.Framework.DependencyInjection.SourceGenerator;

            [AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
            public class InjectAttribute : Attribute
        {

                // public string Name{get;set;}

                /// <summary>
                /// /// 使用 动态 Web Api
                /// </summary>
                //public InjectAttribute(string name)
            public InjectAttribute()
            {
                //Name=name;
            }
        }
        """, Encoding.UTF8));

        // 获取所有的类符号
        // var classSymbols = context.Compilation.SourceModule.GlobalNamespace.GetNamespaceMembers();

        foreach (var @class in classes)
        {
            // 获取类的命名空间
            var namespaceName = @class.Parent is NamespaceDeclarationSyntax namespaceDeclaration
                ? namespaceDeclaration.Name.ToString() : @class.Parent is FileScopedNamespaceDeclarationSyntax namespaceDeclarationSyntax ? namespaceDeclarationSyntax.Name.ToString() : null;
            // 获取类名称
            var className = @class.Identifier.Text;
            // 获取所有的字段符号
            var classSymbol = context.Compilation.GetSemanticModel(@class.SyntaxTree).GetDeclaredSymbol(@class);
            var fieldSymbols = classSymbol.GetMembers().OfType<IFieldSymbol>();
            // 获取所有的依赖项
            // var dependencies = fieldSymbols.Select(f => f.Type.Name).ToList();
            var dependencieList = new List<string>();
            //
            var fieldInitializationList = new List<string>();

            foreach (var fieldSymbol in fieldSymbols)
            {
                // 检查是否有特定的特性
                var hasInjectAttribute = fieldSymbol.GetAttributes()
                    .Any(attr => attr.AttributeClass.Name == "InjectAttribute" || attr.AttributeClass.Name == "Inject");

                // 读取特性 InjectAttribute 中的 属性和值
                //var injectAttribute = fieldSymbol.GetAttributes().FirstOrDefault(attr => attr.AttributeClass.Name == "InjectAttribute" || attr.AttributeClass.Name == "Inject");
                //if (injectAttribute != null)
                //{
                //    var name = injectAttribute.ConstructorArguments.FirstOrDefault().Value?.ToString();
                //    if (!string.IsNullOrWhiteSpace(name))
                //    {
                //        dependencies.Add(name);
                //        continue;
                //    }
                //}

                if (hasInjectAttribute)
                {
                    // 移除第一个下划线 fieldSymbol.Name
                    var name = fieldSymbol.Name;
                    if (fieldSymbol.Name.StartsWith("_"))
                    {
                        name = fieldSymbol.Name.Remove(0, 1);
                    }

                    dependencieList.Add(fieldSymbol.Type.Name + " " + name);

                    fieldInitializationList.Add("this." + fieldSymbol.Name + " = " + name + ";");
                }
            }

            if (dependencieList == null || dependencieList.Count == 0) continue;

            // 这个字段有 "Inject" 特性
            // 在这里处理这个字段
            // 为每个依赖项生成一个私有字段
            //var fields = dependencies.Select(d => $"private readonly {d} _{d.ToLower()};");

            // 生成一个包含所有依赖项参数的构造函数，并在构造函数中初始化私有字段
            var constructorParameters = string.Join(", ", dependencieList);
            var fieldInitializations = string.Join("\n", fieldInitializationList);
            //{/*string.Join("\n", fields)*/}
            var classCode = $@"

                // <auto-generated/>
                namespace {namespaceName};

                public partial class {className}
                {{
       
                    public {className}({constructorParameters})
                    {{
                        {fieldInitializations}
                    }}
                }}
";

            context.AddSource($"{className}.g", SourceText.From(classCode, Encoding.UTF8));

        }
    }
}